#rem
	TimelineFX Module by Peter Rigby
	
	Copyright (c) 2012 Peter J Rigby
	
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	
	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.
	
	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

#END

Import timelinefx

Alias Node = list.Node

Class tlParticle Extends tlGameObject

	Public
	
	'---------------------------------
	Field lifetime:Float								'Time that the particle lives for
	'---------------------------------
	Field weightvariation:Float							'Particle weight variation
	Field weight:Float
	Field baseweight:Float
	Field gravity:Float
	Field scalevariationx:Float							'particle size x variation
	Field scalevariationy:Float							'particle size y variation
	Field gsizex:Float									'Particle global size x
	Field gsizey:Float									'Particle global size y
	Field width:Float
	Field height:Float
	Field imagescalex:Float
	Field imagescaley:Float
	Field sprite:tlShape
	Field animateonce:Int
	'---------------------------------
	Field velvariation:Float							'velocity variation
	Field velseed:Float									'rnd seed
	Field basespeed:Float
	Field speed_vec:tlVector2
	Field speed:Float
	'---------------------------------
	Field spinvariation:Float							'variation of spin speed
	Field spin:Float									'The current amount of spin
	'---------------------------------
	Field directionvariaion:Float						'Direction variation at spawn time
	Field direction:Float
	Field directionlocked:Int
	Field timetracker:Int								'This is used to keep track of game ticks so that some things can be updated between specific time intervals
	Field randomdirection:Float							'current direction of the random motion that pulls the particle in different directions
	Field randomspeed:Float								'random speed to apply to the particle movement
	Field emissionangle:Float							'Direction variation at spawn time
	Field releasesingleparticle:Int						'set to true to release single particles and let them decay and die
	'---------------------------------
	Field acycles:Int
	Field ccycles:Int
	Field rptageA:Float
	Field rptageC:Float
	'---------------------------------
	Field pm:tlParticleManager							'link to the particle manager
	Field layer:Int										'layer the particle belongs to
	Field effectlayer:Int								'The effect layer the particle belongs too in the particle manager
	Field emitter:tlEmitter								'tlemitter it belongs to
	Field corecomponent:tlParticleCoreComponent			'quick access the core component
	Field link:Node<tlParticle>
	
	Method New()
		speed_vec = New tlVector2(0, 0)
		ImageBox = New tlBox(0, 0, 1, 1)
		RotateVector = New tlVector2(0, 0)
	End Method
	
	Method Sprite:tlShape() Property
		Return sprite
	End
	
	Method Sprite(v:tlShape) Property
		sprite = v
	End
	
	Method ParticleManager:tlParticleManager() Property
		Return pm
	End
	
	Method ParticleManager(v:tlParticleManager) Property
		pm = v
	End
	
	Method AnimateOnce:Int() Property
		Return animateonce
	End
	
	Method AnimateOnce(v:Int) Property
		animateonce = v
	End
	
	Method Render(tween:Float, origin:tlVector2 = Null, RenderChildren:Int = True, ScreenBox:tlBox = Null)
		If age Or emitter.singleparticle
			If ScreenBox And _ImageBox
				If ContainingBox
					If Not ScreenBox.BoundingBoxOverlap(ContainingBox) Return
				Else
					If Not ScreenBox.BoundingBoxOverlap(ImageBox) Return
				End If
			End If
			If autocenter
				image.Image.SetHandle(image.Width / 2, image.Height / 2)
			Else
				image.Image.SetHandle(handle_vec.x, handle_vec.y)
			End If
			SetBlend blendmode
			Local tv:Float
			If emitter.anglerelative
				If Abs(_oldWorldRotation - WorldRotation) > 180
					tv = TweenValues(Abs(oldWorldRotation - 360), WorldRotation, tween)
				Else
					tv = TweenValues(oldWorldRotation, WorldRotation, tween)
				End If
			Else
				If Abs(oldLocalRotation - LocalRotation) > 180
					tv = TweenValues(Abs(oldLocalRotation - 360), LocalRotation, tween)
				Else
					tv = TweenValues(oldLocalRotation, LocalRotation, tween)
				End If
			End If
			Rotate tv
			Local tx:Float = TweenValues(OldWorldScaleVector.x, WorldScaleVector.x, tween)
			Local ty:Float = TweenValues(OldWorldScaleVector.y, WorldScaleVector.y, tween)
			tv = TweenValues(OldZoom, Zoom, tween)
			If tv = 1
				Scale tx, ty
			Else
				Scale tx * tv, ty * tv
			End If
			SetColor red, green, blue
			SetAlpha alpha
			If animating
				tv = TweenValues(oldCurrentFrame, CurrentFrame, tween)
				If tv < 0
					tv = sprite.Frames + tv Mod sprite.Frames
					If tv = sprite.Frames
						tv = 0
					End If
				Else
					tv = tv Mod sprite.Frames
				End If
			Else
				tv = CurrentFrame
			End If
			DrawImage(sprite.Image, TweenValues(OldWorldVector.x, WorldVector.x, tween) - origin.x, TweenValues(OldWorldVector.y, WorldVector.y, tween) - origin.y, tv)
			If rendercollisionbox
				Scale 1, 1
				Rotate 0
				SetColor 255, 0, 255
				SetAlpha 0.5
				If collisionbox collisionbox.Draw(origin.x, origin.y, False)
				SetColor 255, 255, 0
				ImageBox.Draw()
			End If
		End If
		If RenderChildren
			For Local o:tlGameObject = EachIn children
				o.Render(tween, origin,, ScreenBox)
			Next
		End If
	End Method
	
	Method Reset()
		Age = 0
		WorldVector.SetPosition(0, 0)
		Zoom = 1
		Image = Null
		'Sprite = Null
		If ImageBox
			ImageBox.Data = Null
		End If
		If ContainingBox
			ContainingBox.Data = Null
		End If
		Dead = False
		ClearChildren()
		ChildCount = 0
		speed = 0
		directionvariaion = 0
		direction = 0
		directionlocked = False
		randomspeed = 0
		randomdirection = 0
		Parent = Null
		RootParent = Null
		acycles = 0
		ccycles = 0
		rptageA = 0
		rptageC = 0
		releasesingleparticle = 0
		gravity = 0
		weight = 0
		spin = 0
		corecomponent.emitter = Null
		emitter = Null
		Destroyed = False
	End Method
	
	Method Update:Int()
	
		UpdateTime = tp_UPDATE_FREQUENCY

		Capture()
						
		'transform the object
		TForm()
		
		'update components
		'UpdateComponents()
		corecomponent.Update()
		
		'update the children		
		UpdateChildren()
		
		'update the collision box
		'If _collisionbox updatecollisionbox()
		UpdateImageBox()
		If Parent
			If ContainingBox
				Parent.UpdateContainingBox(ContainingBox.tl_corner.x, ContainingBox.tl_corner.y, ContainingBox.br_corner.x, ContainingBox.br_corner.y)
			Else
				Parent.UpdateContainingBox(ImageBox.tl_corner.x, ImageBox.tl_corner.y, ImageBox.br_corner.x, ImageBox.br_corner.y)
			End If
		End If
		If UpdateContainerBox ReSizeContainingBox()
		
		'animate the image
		Animate()
		
	End Method
	
	Method TForm()
		'set the Matrix if it is relative to the Parent
		If Relative
			Matrix.Set(Cos(LocalRotation), Sin(LocalRotation), -Sin(LocalRotation), Cos(LocalRotation))
		End If
		
		'calculate where the particle is in the world
		If Parent And Relative
			Zoom = Parent.Zoom
			Matrix = Matrix.Transform(Parent.Matrix)
			RotateVector = Parent.Matrix.TransformVector(LocalVector)
			If Zoom = 1
				WorldVector.x = Parent.WorldVector.x + RotateVector.x
				WorldVector.y = Parent.WorldVector.y + RotateVector.y
			Else
				WorldVector.x = Parent.WorldVector.x + RotateVector.x * Zoom
				WorldVector.y = Parent.WorldVector.y + RotateVector.y * Zoom
			End If
			WorldRotation = Parent.WorldRotation + LocalRotation
			If WorldRotation > 360 WorldRotation = WorldRotation Mod 360
		Else
			WorldRotation = LocalRotation
			WorldVector.SetPositionByVector(LocalVector)
		End If
		
		WorldScaleVector.SetPositionByVector(ScaleVector)
		
	End Method
	
	Method Destroy()
		pm.ReleaseParticle(Self)
		For Local o:tlGameObject = EachIn GetChildren
			o.Destroy()
		Next
		Reset()
	End Method

	Method Animate()
		If Animating
			CurrentFrame += FrameRate / UpdateTime
			If animateonce
				If CurrentFrame > Sprite.Frames - 1
					CurrentFrame = Sprite.Frames - 1
				Else If CurrentFrame <= 0
					CurrentFrame = 0
				End If
			End If
		End If
	End Method
	
	Method UpdateImageBox()
		ImageBox.SetPosition(WorldVector.x, WorldVector.y)
		If OldWorldScaleVector.x <> WorldScaleVector.x Or OldWorldScaleVector.y <> WorldScaleVector.y
			Local maxdiminesion:Float = Max(WorldScaleVector.x, WorldScaleVector.y)
			ImageBox.SetScale(maxdiminesion, maxdiminesion)
		End If
	End Method
End
